/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.editor.abstracteditor;

import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.KeyStroke;
import org.eclipse.gef.MouseWheelHandler;
import org.eclipse.gef.MouseWheelZoomHandler;
import org.eclipse.gef.SnapToGeometry;
import org.eclipse.gef.SnapToGrid;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.AlignmentAction;
import org.eclipse.gef.ui.actions.DirectEditAction;
import org.eclipse.gef.ui.actions.GEFActionConstants;
import org.eclipse.gef.ui.actions.MatchHeightAction;
import org.eclipse.gef.ui.actions.MatchWidthAction;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.gef.ui.actions.ToggleGridAction;
import org.eclipse.gef.ui.actions.ToggleSnapToGeometryAction;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.palette.PaletteViewerProvider;
import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.actions.AdaptDimension;
import com.cea.papyrus.core.actions.ApplyStereotypeAction;
import com.cea.papyrus.core.actions.CloseDiagramAction;
import com.cea.papyrus.core.actions.ExtendedActionRegistry;
import com.cea.papyrus.core.actions.OpenDiagramAction;
import com.cea.papyrus.core.actions.delete.DeleteFromDiagramAction;
import com.cea.papyrus.core.actions.delete.DeleteFromModelAction;
import com.cea.papyrus.core.actions.imports.ImportLibraryFromRepositoryAction;
import com.cea.papyrus.core.actions.imports.ImportPackageFromCurrentModelAction;
import com.cea.papyrus.core.actions.imports.ImportPackageFromFileAction;
import com.cea.papyrus.core.actions.imports.ImportPackageFromWorkspaceAction;
import com.cea.papyrus.core.actions.imports.ImportProfilesAsLibraryFromRepositoryAction;
import com.cea.papyrus.core.actions.profile.DisplayDefinitionHistoryAction;
import com.cea.papyrus.core.actions.selectcopypaste.CopyAction;
import com.cea.papyrus.core.actions.selectcopypaste.PasteAction;
import com.cea.papyrus.core.dnd.GraphicalPageWithFlyoutPaletteDropTargetListener;
import com.cea.papyrus.core.editor.DiagramEditorPage;
import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;

/**
 * 
 * 
 * @author Patrick Tessier
 */

public abstract class AbstractGraphicalPageWithFlyoutPalette extends GraphicalEditorWithFlyoutPalette 
implements DiagramEditorPage, ITabbedPropertySheetPageContributor{

	//Darpan
	public AbstractGraphicalPageWithFlyoutPalette() {
		
	}

	/**
	 * 
	 */
	protected Diagram diagram=null;                //the  model

	/**
	 * 
	 */
	protected static int channel=4;  

	/**
	 * 
	 */
	protected GraphicalViewer viewer;

	/**
	 * 
	 */
	protected PapyrusGraphicalViewerKeyHandler sharedKeyHandler;

	/**
	 * 
	 */
	protected ContextMenuProvider cmProvider =null;

	/**
	 * 
	 */
	protected ModelManager modelMngr; 

	/* Tabbed properties page */
	/**
	 * 
	 */
	protected TabbedPropertySheetPage tabbedPropertySheetPage=null;

	protected ExtendedActionRegistry actionRegistry;

	/**
	 * Creates a new AbstractGraphicalPageWithFlyoutPalette, with a default Edit Domain.
	 * @param diagram the diagram displayed by this editor 
	 * @param modelMngr the instance of the model manager for the edited model
	 */
	public AbstractGraphicalPageWithFlyoutPalette( Diagram diagram, ModelManager modelMngr){
		setEditDomain(new DefaultEditDomain(this));
		this.diagram = diagram;
		this.modelMngr = modelMngr;
		setPartName(diagram.getName());
	}


	/**
	 * Creates a new AbstractGraphicalPageWithFlyoutPalette, with a specified Edit Domain.
	 * <p>usually, this is used when the editing domain is the same as the parent editor,
	 * in case of a multipage editor</p>
	 * @param diagram the diagram displayed by this editor
	 * @param modelMngr the instance of the model manager for the edited model
	 * @param editDomain the command stack shared among all editors of the MultiDiagramEditor 
	 * @deprecated Use {@link #AbstractGraphicalPageWithFlyoutPalette(Diagram,ModelManager,CommandStackUtils,ActionRegistry)} instead
	 */
	public AbstractGraphicalPageWithFlyoutPalette( Diagram diagram, ModelManager modelMngr, CommandStack commandStack){
		this(diagram, modelMngr, commandStack, new ActionRegistry());
	}


	/**
	 * Creates a new AbstractGraphicalPageWithFlyoutPalette, with a specified Edit Domain.
	 * <p>usually, this is used when the editing domain is the same as the parent editor,
	 * in case of a multipage editor</p>
	 * @param diagram the diagram displayed by this editor
	 * @param modelMngr the instance of the model manager for the edited model
	 * @param actionRegistry TODO
	 * @param editDomain the command stack shared among all editors of the MultiDiagramEditor 
	 */
	public AbstractGraphicalPageWithFlyoutPalette( Diagram diagram, ModelManager modelMngr, CommandStack commandStack, ActionRegistry actionRegistry){
		setEditDomain(new DefaultEditDomain(this));
		getEditDomain().setCommandStack(commandStack);
		this.diagram = diagram;
		this.modelMngr = modelMngr;
		setPartName(diagram.getName());
		setTitleImage(modelMngr.getLabelProvider().getImage(diagram));
		this.actionRegistry = new ExtendedActionRegistry(actionRegistry);
	}

	
	@Override
	protected ExtendedActionRegistry getActionRegistry() {
		return actionRegistry;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditor#dispose()
	 */
	@Override
	public void dispose() {
		getCommandStack().removeCommandStackListener(this);
		getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this);
		getEditDomain().setActiveTool(null);
		getActionRegistry().dispose();
		
		// Clear out the property change listeners as we
		// should not be notifying anyone after the part
		// has been disposed.
		clearListeners();
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditor#commandStackChanged(java.util.EventObject)
	 */
	@Override
	public void commandStackChanged(EventObject event) {
		Debug.debug(this,"DiagramEditor event:"+event,channel);
		// viewer.getContents().refresh();
		//viewer.getRootEditPart().refresh();
		//viewer.setContents(getDiagramModel());	
		super.firePropertyChange(IEditorPart.PROP_DIRTY);
		super.commandStackChanged(event);
	}

	/**
	 * use ro configure the context menu.
	 */
	protected void configureContextMenuProvider(){
		viewer = getGraphicalViewer();
		viewer.setContextMenu(cmProvider);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
	 */
	/**
	 * 
	 */
	@Override
	protected void configureGraphicalViewer() {
		super.configureGraphicalViewer();
		viewer = getGraphicalViewer();

		ScalableFreeformRootEditPart root = new ScalableFreeformRootEditPart();
		viewer.setRootEditPart(root);
		// viewer.setKeyHandler(new PapyrusGraphicalViewerKeyHandler(viewer).setParent(getCommonKeyHandler()));
		viewer.setKeyHandler(getCommonKeyHandler());
		// Scroll-wheel Zoom
		viewer.setProperty(MouseWheelHandler.KeyGenerator.getKey(SWT.MOD1), 
				MouseWheelZoomHandler.SINGLETON);

		//		 Snap to Geometry property
		getGraphicalViewer().setProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED, false);


		// Grid properties
		viewer.setProperty(SnapToGrid.PROPERTY_GRID_ENABLED, false);

		// We keep grid visibility and enablement in sync
		viewer.setProperty(SnapToGrid.PROPERTY_GRID_VISIBLE, false);

		List zoomLevels = new ArrayList(3);
		zoomLevels.add(ZoomManager.FIT_ALL);
		zoomLevels.add(ZoomManager.FIT_WIDTH);
		zoomLevels.add(ZoomManager.FIT_HEIGHT);
		root.getZoomManager().setZoomLevelContributions(zoomLevels);

		// Keyboard zoom
		IAction zoomIn = new ZoomInAction(root.getZoomManager());
		IAction zoomOut = new ZoomOutAction(root.getZoomManager());
		getActionRegistry().registerAction(zoomIn);
		getActionRegistry().registerAction(zoomOut);
		getSite().getKeyBindingService().registerAction(zoomIn);
		getSite().getKeyBindingService().registerAction(zoomOut);	

		//		 snap Actions		
		IAction snapAction = new ToggleSnapToGeometryAction(getGraphicalViewer());
		getActionRegistry().registerAction(snapAction);

		IAction showGrid = new ToggleGridAction(getGraphicalViewer());
		getActionRegistry().registerAction(showGrid);
		
		Listener listener = new Listener() {
			public void handleEvent(Event event) {
				handleActivationChanged(event);
			}
		};
		//getGraphicalControl().addListener(SWT.Activate, listener);
		//getGraphicalControl().addListener(SWT.Deactivate, listener);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void createActions() {
		super.createActions();
		final ActionRegistry registry = getActionRegistry();

		// graphical mangement
		registerSelectionAction(registry, new MatchHeightAction(this));
		registerSelectionAction(registry, new MatchWidthAction(this));
		registerSelectionAction(registry, new AdaptDimension(this));

		// edit actions
		registerSelectionAction(registry, new DeleteFromDiagramAction(this));
		registerSelectionAction(registry, new DeleteFromModelAction(this));
		registerSelectionAction(registry, new PasteAction(this));
		registerSelectionAction(registry, new CopyAction(this));
		
		// alignement action
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.LEFT));
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.RIGHT));
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.TOP));
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.BOTTOM));
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.CENTER));
		registerSelectionAction(registry, new AlignmentAction((IWorkbenchPart)this, PositionConstants.MIDDLE));
		
		// diagram mangement
		registerSelectionAction(registry, new CloseDiagramAction(this));
		registerSelectionAction(registry, new OpenDiagramAction(this));
		
		// import package actions
		registerSelectionAction(registry, new ImportPackageFromCurrentModelAction(this));
		registerSelectionAction(registry, new ImportPackageFromFileAction(this));
		registerSelectionAction(registry, new ImportLibraryFromRepositoryAction(this));
		registerSelectionAction(registry, new ImportProfilesAsLibraryFromRepositoryAction(this));
		registerSelectionAction(registry, new ImportPackageFromWorkspaceAction(this));
		
		// misc
		registerSelectionAction(registry, new ApplyStereotypeAction(this));
		registerSelectionAction(registry, new DirectEditAction((IWorkbenchPart)this));
		registerSelectionAction(registry, new DisplayDefinitionHistoryAction((IWorkbenchPart)this));
	}
	
	protected void registerSelectionAction(ActionRegistry registry, SelectionAction action) {
		registry.registerAction(action);
		getSelectionActions().add(action.getId());
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#createPaletteViewerProvider()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	@Override
	protected PaletteViewerProvider createPaletteViewerProvider() {

		return new PaletteViewerProvider(getEditDomain()) {
			@Override
			protected void configurePaletteViewer(PaletteViewer viewer) {
				super.configurePaletteViewer(viewer);
				// create a drag source listener for this palette viewer
				// together with an appropriate transfer drop target listener, this will enable
				// model element creation by dragging a CombinatedTemplateCreationEntries 
				// from the palette into the editor
				// @see ShapesEditor#createTransferDropTargetListener()
				viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
			}
		};
	}

	/**
	 * Saves the multi-page editor's document.
	 * 
	 * @param monitor 
	 */
	@Override
	public void doSave(IProgressMonitor monitor) {
		super.firePropertyChange(PROP_DIRTY);

	}

	/**
	 * 
	 * 
	 * @param event 
	 */
	protected void handleActivationChanged(Event event) {
		IAction copy = null;
		if (event.type == SWT.Deactivate) {
			copy = getActionRegistry().getAction(ActionFactory.COPY.getId());
		}
		if (getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId()) 
				!= copy) {
			getEditorSite().getActionBars().setGlobalActionHandler(
					ActionFactory.COPY.getId(), copy);
			getEditorSite().getActionBars().updateActionBars();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#initializeGraphicalViewer()
	 */
	/**
	 * 
	 */
	@Override
	protected void initializeGraphicalViewer(){
		GraphicalViewer viewer = getGraphicalViewer();
		viewer.getControl().addDisposeListener(new org.eclipse.swt.events.DisposeListener() {
			public void widgetDisposed(org.eclipse.swt.events.DisposeEvent e) {
			}
		});
		// set the contents of this editor
		// This start the creation of editparts
		viewer.setContents(getDiagramModel()); 

		// DND setup
		getGraphicalViewer().addDropTargetListener(new GraphicalPageWithFlyoutPaletteDropTargetListener(viewer));
		getSite().registerContextMenu(
				IPapyrusUIConstants.OUTLINE_POPUP_MENU_ID,
				cmProvider, getSite().getSelectionProvider()); 
	
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditor#isSaveAsAllowed()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getAdapter(java.lang.Class)
	 */
	/**
	 * 
	 * 
	 * @param adapter 
	 * 
	 * @return 
	 */
	@Override
	public Object getAdapter(Class adapter) {
		if (adapter == IPropertySheetPage.class) {
			// Do not test if tabbedPropertySheetPage is null before calling new
			// this is managed by Eclipse which only call current method when necessary
			tabbedPropertySheetPage = new TabbedPropertySheetPage(this);

			return tabbedPropertySheetPage;
		}
		
		if(adapter == ModelManager.class) {
			return modelMngr;
		}
		
		if(adapter == EditingDomain.class) {
			return modelMngr.getDiResourceSet().getEditingDomain();
		}
		
		return super.getAdapter(adapter);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	public String getContributorId() {
		return "TreeOutlinePage";
	}

	/**
	 * Returns the KeyHandler with common bindings for both the Graphical Views.
	 * For example, delete is a common action.
	 * 
	 * @return 
	 */
	protected KeyHandler getCommonKeyHandler(){
		if (sharedKeyHandler == null){
			sharedKeyHandler = new PapyrusGraphicalViewerKeyHandler(this.getGraphicalViewer());
			// ctrl+l = adapt dimension of the figure
			sharedKeyHandler.put(
					KeyStroke.getPressed('\f', 108, SWT.CTRL), getActionRegistry().getAction(AdaptDimension.ADAPT_DIMENSION_ACTION_ID));
			sharedKeyHandler.put(
					KeyStroke.getPressed(SWT.F2, 0), getActionRegistry().getAction(GEFActionConstants.DIRECT_EDIT));
			sharedKeyHandler.put(
					KeyStroke.getPressed(SWT.DEL, 127, SWT.SHIFT), getActionRegistry().getAction(DeleteFromModelAction.DELETE_FROM_MODEL_ACTION_ID));
			sharedKeyHandler.put(
					KeyStroke.getPressed(SWT.DEL, 127, 0), getActionRegistry().getAction(DeleteFromDiagramAction.DELETE_FROM_DIAGRAM_ACTION_ID));
		}
		return sharedKeyHandler;
	}

	/**
	 * Return the underlying graphical viewer.
	 * Used by the multipage editor to set the current viwer for selection synchronization.
	 * 
	 * @return 
	 */
	@Override
	public GraphicalViewer getGraphicalViewer() {
		return super.getGraphicalViewer();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.editor.DiagramEditorPage#getDiagramModel()
	 */
	public Diagram getDiagramModel() {
		return diagram;
	}

	/**
	 * Mark the command stack of all sub-editors.
	 */
	public void markSaveLocation() {
		getCommandStack().markSaveLocation();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.editor.DiagramEditorPage#setDisplayName(java.lang.String)
	 */
	/**
	 * 
	 * 
	 * @param string 
	 */
	public void setDisplayName(String string) {

	}

	/**
	 * Update the selectionActions list when the editor is selected as a page of a
	 * MultiPageEditorPart.
	 * 
	 * @param part 
	 * @param selection 
	 */
	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		IEditorPart editor = getSite().getPage().getActiveEditor();
		if ( editor instanceof MultiPageEditorPart){
			updateActions(getSelectionActions());
		}

		super.selectionChanged(part, selection);
	}

	/**
	 * 
	 * 
	 * @param input 
	 */
	@Override
	protected void setInput(IEditorInput input) {
		super.setInput(input);
	}


}
